﻿#nullable enable

using System.Data.Common;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using PHMEE.CommonUtils;
using PHMEE.TDengineInfrastructure;
using TDengine.Data.Client;
using Volo.Abp.Domain.Repositories;

namespace PHMEE.EnergyEfficiency;

public class LogAbstractRepository : BaseTdRepository, ILogAbstractRepository
{
    private readonly ILogger<LogAbstractRepository> _logger;

    /// <summary>
    /// LogAbstract 位于能效库
    /// </summary>
    private const DbPrefixEnum DbPrefix = DbPrefixEnum.Ee;

    /// <summary>
    /// LogAbstract 约定好的子表名前缀
    /// </summary>
    private const string SubTablePrefix = "la";

    /// <summary>
    /// 各 sql 语句的 VALUES 前的部分，含 id
    /// </summary>
    private const string SubTableValues =
        "ts,id,creation_time,last_modified_time,imo,date_utc,time_utc,voyage_from,voyage_to,voyage_number,offhire_reasons,event,time_since_previous_report,time_elapsed_sailing,time_elapsed_anchoring,time_elapsed_dp,time_elapsed_ice,time_elapsed_maneuvering,time_elapsed_waiting,time_elapsed_loading_unloading,time_elapsed_drifting,distance,latitude_degree,latitude_minutes,latitude_north_south,longitude_degree,longitude_minutes,longitude_east_west,cargo_mt,cargo_m3,passengers,cargo_ceu,cargo_total_teu,cargo_total_full_teu,cargo_full_reefer_teu,reefer_20_chilled,reefer_40_chilled,reefer_20_frozen,reefer_40_frozen,me_consumption_hfo,me_consumption_lfo,me_consumption_mgo,me_consumption_mdo,me_consumption_lshfo,me_consumption_lslfo,me_consumption_lsmgo,me_consumption_ulsfo2020,me_consumption_ulslfo2020,me_consumption_ulsmdo2020,me_consumption_ulsmgo2020,me_consumption_vlsfo2020,me_consumption_vlslfo2020,me_consumption_lpgp,me_consumption_lpgb,me_consumption_lng,me_consumption_m,me_consumption_e,me_consumption_o,me_consumption_o_type,ae_consumption_hfo,ae_consumption_lfo,ae_consumption_mgo,ae_consumption_mdo,ae_consumption_lshfo,ae_consumption_lslfo,ae_consumption_lsmgo,ae_consumption_ulsfo2020,ae_consumption_ulslfo2020,ae_consumption_ulsmdo2020,ae_consumption_ulsmgo2020,ae_consumption_vlsfo2020,ae_consumption_vlslfo2020,ae_consumption_lpgp,ae_consumption_lpgb,ae_consumption_lng,ae_consumption_m,ae_consumption_e,ae_consumption_o,ae_consumption_o_type,ae_emrg_cons_hfo,ae_emrg_cons_lfo,ae_emrg_cons_mgo,ae_emrg_cons_mdo,ae_emrg_cons_lshfo,ae_emrg_cons_lslfo,ae_emrg_cons_lsmgo,ae_emrg_cons_ulsfo2020,ae_emrg_cons_ulslfo2020,ae_emrg_cons_ulsmdo2020,ae_emrg_cons_ulsmgo2020,ae_emrg_cons_vlsfo2020,ae_emrg_cons_vlslfo2020,ae_emrg_cons_lpgp,ae_emrg_cons_lpgb,ae_emrg_cons_lng,ae_emrg_cons_m,ae_emrg_cons_e,ae_emrg_cons_o,ae_emrg_cons_o_type,boiler_consumption_hfo,boiler_consumption_lfo,boiler_consumption_mgo,boiler_consumption_mdo,boiler_consumption_lshfo,boiler_consumption_lslfo,boiler_consumption_lsmgo,boiler_consumption_ulsfo2020,boiler_consumption_ulslfo2020,boiler_consumption_ulsmdo2020,boiler_consumption_ulsmgo2020,boiler_consumption_vlsfo2020,boiler_consumption_vlslfo2020,boiler_consumption_lpgp,boiler_consumption_lpgb,boiler_consumption_lng,boiler_consumption_m,boiler_consumption_e,boiler_consumption_o,boiler_consumption_o_type,inert_gas_consumption_hfo,inert_gas_consumption_lfo,inert_gas_consumption_mgo,inert_gas_consumption_mdo,inert_gas_consumption_lshfo,inert_gas_consumption_lslfo,inert_gas_consumption_lsmgo,inert_gas_consumption_ulsfo2020,inert_gas_consumption_ulslfo2020,inert_gas_consumption_ulsmdo2020,inert_gas_consumption_ulsmgo2020,inert_gas_consumption_vlsfo2020,inert_gas_consumption_vlslfo2020,inert_gas_consumption_lpgp,inert_gas_consumption_lpgb,inert_gas_consumption_lng,inert_gas_consumption_m,inert_gas_consumption_e,inert_gas_consumption_o,inert_gas_consumption_o_type,incinerator_consumption_o,incinerator_consumption_o_type,hfo_rob,lfo_rob,mgo_rob,mdo_rob,lshfo_rob,lslfo_rob,lsmgo_rob,ulsfo2020_rob,ulslfo2020_rob,ulsmdo2020_rob,ulsmgo2020_rob,vlsfo2020_rob,vlslfo2020_rob,lpgp_rob,lpgb_rob,lng_rob,methanol_rob,ethanol_rob,o_rob,o_rob_type,cargo_heating_consumption_hfo,cargo_heating_consumption_lfo,cargo_heating_consumption_mgo,cargo_heating_consumption_mdo,cargo_heating_consumption_lshfo,cargo_heating_consumption_lslfo,cargo_heating_consumption_lsmgo,cargo_heating_consumption_ulsfo2020,cargo_heating_consumption_ulslfo2020,cargo_heating_consumption_ulsmdo2020,cargo_heating_consumption_ulsmgo2020,cargo_heating_consumption_vlsfo2020,cargo_heating_consumption_vlslfo2020,cargo_heating_consumption_lpgp,cargo_heating_consumption_lpgb,cargo_heating_consumption_lng,cargo_heating_consumption_m,cargo_heating_consumption_e,cargo_heating_consumption_o,cargo_heating_consumption_o_type,dpp_cargo_pump_consumption_mdo,dpp_cargo_pump_consumption_o,dpp_cargo_pump_consumption_o_type,dp_consumption_hfo,dp_consumption_lfo,dp_consumption_mgo,dp_consumption_mdo,dp_consumption_lshfo,dp_consumption_lslfo,dp_consumption_lsmgo,dp_consumption_ulsfo2020,dp_consumption_ulslfo2020,dp_consumption_ulsmdo2020,dp_consumption_ulsmgo2020,dp_consumption_vlsfo2020,dp_consumption_vlslfo2020,dp_consumption_lpgp,dp_consumption_lpgb,dp_consumption_lng,dp_consumption_m,dp_consumption_e,dp_consumption_o,dp_consumption_o_type,reefer_work,reefer_sfoc,reefer_fuel_type,reefer_fuel_bdn,cargo_cooling_work,cargo_cooling_sfoc,cargo_cooling_fuel_type,cargo_cooling_fuel_bdn,discharge_pump_work,discharge_pump_sfoc,discharge_pump_fuel_type,discharge_pump_fuel_bdn,shore_side_electricity_reception";

    public LogAbstractRepository(IOptionsSnapshot<TDengineOptions> tdengineOptions,
        ILogger<LogAbstractRepository> logger) : base(tdengineOptions)
    {
        _logger = logger;
    }

    /// <summary>
    /// 获取子表名
    /// </summary>
    /// <param name="vesselId"></param>
    /// <returns></returns>
    private static string GetSubTableName(Guid vesselId)
    {
        return $"{SubTablePrefix}_{vesselId:N}";
    }

    /// <summary>
    /// 根据 ts 查询 LogAbstract 数据
    /// </summary>
    /// <param name="vesselId"></param>
    /// <param name="ts"></param>
    /// <returns></returns>
    /// <exception cref="TDengineRepositoryException"></exception>
    public async Task<LogAbstract?> GetOrDefaultAsync(Guid vesselId, DateTime ts)
    {
        try
        {
            string dbName = PhmeeConst.GetDbName(DbPrefix, vesselId);
            string subTableName = GetSubTableName(vesselId);

            await using var command = TDConnection.CreateCommand();

            command.CommandText =
                $"SELECT {SubTableValues} FROM {dbName}.{subTableName} WHERE ts = '{ts.ToFormattedUtcString()}';";

            await using var reader = await command.ExecuteReaderAsync();

            if (!await reader.ReadAsync())
            {
                return null;
            }

            var result = MapFromDbReader(reader);

            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"TDengine 仓储: {nameof(LogAbstractRepository)}.{nameof(GetOrDefaultAsync)} 失败");
            throw new TDengineRepositoryException(vesselId, ts, null, null, "根据 ts 查询 LogAbstract 数据失败", ex);
        }
    }

    /// <summary>
    /// 计数，时间前闭后开区间
    /// </summary>
    /// <param name="vesselId"></param>
    /// <param name="startDateTimeUtc"></param>
    /// <param name="endDateTimeUtc"></param>
    /// <returns></returns>
    public async Task<int> CountAsync(Guid vesselId, DateTime startDateTimeUtc, DateTime endDateTimeUtc)
    {
        try
        {
            var dbName = PhmeeConst.GetDbName(DbPrefix, vesselId);

            var subTableName = GetSubTableName(vesselId);

            await using var command = TDConnection.CreateCommand();

            command.CommandText =
                $"SELECT COUNT(*) FROM {dbName}.{subTableName} WHERE ts >= '{startDateTimeUtc.ToFormattedUtcString()}' AND ts < '{endDateTimeUtc.ToFormattedUtcString()}';";

            var result = await command.ExecuteScalarAsync();

            if (result is null)
            {
                throw new TDengineRepositoryException(vesselId, null, startDateTimeUtc, endDateTimeUtc,
                    "查询 LogAbstract Count 失败，result 为 null");
            }

            var count = int.Parse(result.ToString()!);
            return count;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"TDengine 仓储: {nameof(LogAbstractRepository)}.{nameof(CountAsync)} 失败");
            throw new TDengineRepositoryException(vesselId, null, startDateTimeUtc, endDateTimeUtc,
                "查询 LogAbstract Count 失败", ex);
        }
    }

    /// <summary>
    /// 时间前闭后开区间查询，按 Ts DESC 排序
    /// </summary>
    /// <param name="vesselId"></param>
    /// <param name="endDateTimeUtc"></param>
    /// <param name="skipCount"></param>
    /// <param name="maxResultCount"></param>
    /// <param name="startDateTimeUtc"></param>
    /// <returns></returns>
    public async Task<List<LogAbstract>> GetListDescAsync(Guid vesselId, DateTime startDateTimeUtc,
        DateTime endDateTimeUtc,
        int skipCount, int maxResultCount)
    {
        try
        {
            var dbName = PhmeeConst.GetDbName(DbPrefix, vesselId);

            var subTableName = GetSubTableName(vesselId);

            await using var command = TDConnection.CreateCommand();

            command.CommandText =
                $"SELECT {SubTableValues} FROM {dbName}.{subTableName} WHERE ts >= '{startDateTimeUtc.ToFormattedUtcString()}' AND ts < '{endDateTimeUtc.ToFormattedUtcString()}' ORDER BY ts DESC LIMIT {maxResultCount} OFFSET {skipCount};";

            await using var reader = await command.ExecuteReaderAsync();

            List<LogAbstract> list = [];

            while (await reader.ReadAsync())
            {
                LogAbstract newInstance = MapFromDbReader(reader);
                list.Add(newInstance);
            }

            return list;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"TDengine 仓储: {nameof(LogAbstractRepository)}.{nameof(GetListDescAsync)} 失败");
            throw new TDengineRepositoryException(vesselId, null, startDateTimeUtc, endDateTimeUtc,
                "查询 LogAbstract List Desc 失败", ex);
        }
    }

    /// <summary>
    /// 时间前闭后开区间查询
    /// </summary>
    /// <param name="vesselId"></param>
    /// <param name="startDateTimeUtc"></param>
    /// <param name="endDateTimeUtc"></param>
    /// <returns></returns>
    public async Task<List<LogAbstract>> GetListClosedOpenAsync(Guid vesselId, DateTime startDateTimeUtc,
        DateTime endDateTimeUtc)
    {
        try
        {
            var dbName = PhmeeConst.GetDbName(DbPrefix, vesselId);

            var subTableName = GetSubTableName(vesselId);

            await using var command = TDConnection.CreateCommand();

            command.CommandText =
                $"SELECT {SubTableValues} FROM {dbName}.{subTableName} WHERE ts >= '{startDateTimeUtc.ToFormattedUtcString()}' AND ts < '{endDateTimeUtc.ToFormattedUtcString()}' ORDER BY ts ASC;";

            await using var reader = await command.ExecuteReaderAsync();

            List<LogAbstract> list = [];

            while (await reader.ReadAsync())
            {
                LogAbstract newInstance = MapFromDbReader(reader);
                list.Add(newInstance);
            }

            return list;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"TDengine 仓储: {nameof(LogAbstractRepository)}.{nameof(GetListClosedOpenAsync)} 失败");
            throw new TDengineRepositoryException(vesselId, startDateTimeUtc, endDateTimeUtc, null,
                "查询 LogAbstract List Closed Open 失败", ex);
        }
    }

    /// <summary>
    /// 时间前开后闭区间查询
    /// </summary>
    /// <param name="vesselId"></param>
    /// <param name="startDateTimeUtc"></param>
    /// <param name="endDateTimeUtc"></param>
    /// <returns></returns>
    public async Task<List<LogAbstract>> GetListOpenClosedAsync(Guid vesselId, DateTime startDateTimeUtc,
        DateTime endDateTimeUtc)
    {
        try
        {
            var dbName = PhmeeConst.GetDbName(DbPrefix, vesselId);

            var subTableName = GetSubTableName(vesselId);

            await using var command = TDConnection.CreateCommand();

            command.CommandText =
                $"SELECT {SubTableValues} FROM {dbName}.{subTableName} WHERE ts > '{startDateTimeUtc.ToFormattedUtcString()}' AND ts <= '{endDateTimeUtc.ToFormattedUtcString()}' ORDER BY ts ASC;";

            await using var reader = await command.ExecuteReaderAsync();

            List<LogAbstract> list = [];

            while (await reader.ReadAsync())
            {
                LogAbstract newInstance = MapFromDbReader(reader);
                list.Add(newInstance);
            }

            return list;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"TDengine 仓储: {nameof(LogAbstractRepository)}.{nameof(GetListOpenClosedAsync)} 失败");
            throw new TDengineRepositoryException(vesselId, startDateTimeUtc, endDateTimeUtc, null,
                "查询 LogAbstract List Open Closed 失败", ex);
        }
    }

    /// <summary>
    /// 获取 time 前（包含 time）最新的一条 “离港” 类型的 Log abstract
    /// </summary>
    /// <param name="vesselId"></param>
    /// <param name="dateTimeUtc"></param>
    /// <returns></returns>
    public async Task<LogAbstract?> GetLatestDepartureTypeLogAbstractOrDefaultBeforeOrEqualTimeAsync(Guid vesselId,
        DateTime dateTimeUtc)
    {
        try
        {
            await using var command = TDConnection.CreateCommand();

            var dbName = PhmeeConst.GetDbName(DbPrefix, vesselId);
            var subTableName = GetSubTableName(vesselId);

            // 查出上一个 Departure 类型（包含 Departure、DepartureEU、DepartureSTS）的事件
            List<string> eventWhereCondition = [];
            foreach (var departureEvent in LogAbstractEventTypeHelper.DepartureEvents)
            {
                eventWhereCondition.Add($"event = {(int)departureEvent}");
            }

            command.CommandText =
                $"SELECT {SubTableValues} FROM {dbName}.{subTableName} WHERE ts <= '{dateTimeUtc.ToFormattedUtcString()}' AND ({string.Join(" OR ", eventWhereCondition)}) ORDER BY ts DESC LIMIT 1;";

            await using var reader = await command.ExecuteReaderAsync();

            if (!await reader.ReadAsync())
            {
                return null;
            }

            var result = MapFromDbReader(reader);
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"TDengine 仓储: {nameof(LogAbstractRepository)}.{nameof(GetLatestDepartureTypeLogAbstractOrDefaultBeforeOrEqualTimeAsync)} 失败");
            throw new TDengineRepositoryException(vesselId, dateTimeUtc, null, null,
                "查询最新的 Departure 类型 LogAbstract 失败", ex);
        }
    }

    /// <summary>
    /// 获取距 DateTime time （包含 time）最近的一条 log abstract
    /// </summary>
    /// <param name="vesselId"></param>
    /// <param name="dateTimeUtc"></param>
    /// <returns></returns>
    public async Task<LogAbstract?> GetLatestLogAbstractOrDefaultAsync(Guid vesselId, DateTime dateTimeUtc)
    {
        try
        {
            var dbName = PhmeeConst.GetDbName(DbPrefix, vesselId);

            var subTableName = GetSubTableName(vesselId);

            await using var command = TDConnection.CreateCommand();

            command.CommandText =
                $"SELECT {SubTableValues} FROM {dbName}.{subTableName} WHERE ts <= '{dateTimeUtc.ToFormattedUtcString()}' ORDER BY ts DESC LIMIT 1;";

            await using var reader = await command.ExecuteReaderAsync();

            if (!await reader.ReadAsync())
            {
                return null;
            }

            var result = MapFromDbReader(reader);
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"TDengine 仓储: {nameof(LogAbstractRepository)}.{nameof(GetLatestLogAbstractOrDefaultAsync)} 失败");
            throw new TDengineRepositoryException(vesselId, dateTimeUtc, null, null, "查询最新的 LogAbstract 失败", ex);
        }
    }

    /// <summary>
    /// 获取距 time （包含 time）最近的一条 Adjustment（调整） log abstract
    /// </summary>
    /// <param name="vesselId"></param>
    /// <param name="dateTimeUtc"></param>
    /// <returns></returns>
    public async Task<LogAbstract?> GetLatestAdjustLogAbstractOrDefaultBeforeOrEqualTimeAsync(Guid vesselId,
        DateTime dateTimeUtc)
    {
        try
        {
            var dbName = PhmeeConst.GetDbName(DbPrefix, vesselId);

            var subTableName = GetSubTableName(vesselId);

            await using var command = TDConnection.CreateCommand();

            // 查出上一个 Adjustment 类型（包含 VoyageAdjustmentStart、VoyageAdjustmentOver）的事件
            List<string> eventWhereCondition = [];
            foreach (var adjustmentEvent in LogAbstractEventTypeHelper.AdjustmentEvents)
            {
                eventWhereCondition.Add($"event = {(int)adjustmentEvent}");
            }

            command.CommandText =
                $"SELECT {SubTableValues} FROM {dbName}.{subTableName} WHERE ts <= '{dateTimeUtc.ToFormattedUtcString()}' AND ({string.Join(" OR ", eventWhereCondition)}) ORDER BY ts DESC LIMIT 1;";

            await using var reader = await command.ExecuteReaderAsync();

            if (!await reader.ReadAsync())
            {
                return null;
            }

            var result = MapFromDbReader(reader);
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"TDengine 仓储: {nameof(LogAbstractRepository)}.{nameof(GetLatestAdjustLogAbstractOrDefaultBeforeOrEqualTimeAsync)} 失败");
            throw new TDengineRepositoryException(vesselId, dateTimeUtc, null, null,
                "查询最新的 Adjustment 类型 LogAbstract 失败", ex);
        }
    }

    /// <summary>
    /// 获取距 time （不包含 time）最早的一条 Adjustment（调整） log abstract
    /// </summary>
    /// <param name="vesselId"></param>
    /// <param name="dateTimeUtc"></param>
    /// <returns></returns>
    public async Task<LogAbstract?> GetEarliestAdjustLogAbstractOrDefaultAfterTimeAsync(Guid vesselId,
        DateTime dateTimeUtc)
    {
        try
        {
            var dbName = PhmeeConst.GetDbName(DbPrefix, vesselId);

            var subTableName = GetSubTableName(vesselId);

            await using var command = TDConnection.CreateCommand();

            // 查出下一个 Adjustment 类型（包含 VoyageAdjustmentStart、VoyageAdjustmentOver）的事件
            List<string> eventWhereCondition = [];
            foreach (var adjustmentEvent in LogAbstractEventTypeHelper.AdjustmentEvents)
            {
                eventWhereCondition.Add($"event = {(int)adjustmentEvent}");
            }

            command.CommandText =
                $"SELECT {SubTableValues} FROM {dbName}.{subTableName} WHERE ts > '{dateTimeUtc.ToFormattedUtcString()}' AND ({string.Join(" OR ", eventWhereCondition)}) ORDER BY ts ASC LIMIT 1;";

            await using var reader = await command.ExecuteReaderAsync();

            if (!await reader.ReadAsync())
            {
                return null;
            }

            var result = MapFromDbReader(reader);
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"TDengine 仓储: {nameof(LogAbstractRepository)}.{nameof(GetEarliestAdjustLogAbstractOrDefaultAfterTimeAsync)} 失败");
            throw new TDengineRepositoryException(vesselId, dateTimeUtc, null, null,
                "查询最早的 Adjustment 类型 LogAbstract 失败", ex);
        }
    }

    /// <summary>
    /// 获取最后一条 LogAbstract
    /// </summary>
    /// <param name="vesselId"></param>
    /// <returns></returns>
    public async Task<LogAbstract?> GetLastLogAbstractOrDefaultAsync(Guid vesselId)
    {
        try
        {
            var dbName = PhmeeConst.GetDbName(DbPrefix, vesselId);

            var subTableName = GetSubTableName(vesselId);

            await using var command = TDConnection.CreateCommand();

            command.CommandText = $"SELECT {SubTableValues} FROM {dbName}.{subTableName} ORDER BY ts DESC LIMIT 1;";

            await using var reader = await command.ExecuteReaderAsync();

            if (!await reader.ReadAsync())
            {
                return null;
            }

            var result = MapFromDbReader(reader);
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"TDengine 仓储: {nameof(LogAbstractRepository)}.{nameof(GetLastLogAbstractOrDefaultAsync)} 失败");
            throw new TDengineRepositoryException(vesselId, null, null, null, "查询最后一条 LogAbstract 失败", ex);
        }
    }

    #region 增删相关函数

    /// <summary>
    /// 插入
    /// </summary>
    /// <param name="logAbstract"></param>
    /// <param name="vesselId"></param>
    /// <exception cref="TDengineRepositoryException"></exception>
    public async Task InsertAsync(LogAbstract logAbstract, Guid vesselId)
    {
        try
        {
            var dbName = PhmeeConst.GetDbName(DbPrefix, vesselId);
            var subTableName = GetSubTableName(vesselId);

            await using var command = TDConnection.CreateCommand();

            var (insertCommandText, insertCommandParameters) =
                GetInsertCommandTextAndParameters(logAbstract, dbName, subTableName);

            command.CommandText = insertCommandText;

            foreach (var (parameterName, parameterValue) in insertCommandParameters)
            {
                command.Parameters.Add(new TDengineParameter(parameterName, parameterValue));
            }

            await command.ExecuteNonQueryAsync();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"TDengine 仓储: {nameof(LogAbstractRepository)}.{nameof(InsertAsync)} 失败");
            throw new TDengineRepositoryException(vesselId, logAbstract.Ts, null, null, "插入 LogAbstract 数据失败", ex);
        }
    }

    /// <summary>
    /// 删除
    /// </summary>
    /// <param name="vesselId"></param>
    /// <param name="ts"></param>
    public async Task DeleteAsync(Guid vesselId, DateTime ts)
    {
        try
        {
            var dbName = PhmeeConst.GetDbName(DbPrefix, vesselId);
            var subTableName = GetSubTableName(vesselId);

            await using var command = TDConnection.CreateCommand();

            var sql =
                $"DELETE FROM {dbName}.{subTableName} WHERE ts = '{ts.ToFormattedUtcString()}';";

            command.CommandText = sql;

            await command.ExecuteNonQueryAsync();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"TDengine 仓储: {nameof(LogAbstractRepository)}.{nameof(DeleteAsync)} 失败");
            throw new TDengineRepositoryException(vesselId, ts, null, null, "删除 LogAbstract 数据失败", ex);
        }
    }

    #endregion 增删相关函数

    private static LogAbstract MapFromDbReader(DbDataReader reader)
    {
        // TODO: O_Type 之类的可空字符串要注意，看看到底是不是查到 null，理应要查到 null

        var result = new LogAbstract();

        result.Ts = reader.GetDateTime(reader.GetOrdinal("ts")).ToUniversalTime();
        result.Id = Guid.Parse(System.Text.Encoding.UTF8.GetString((byte[])reader.GetValue(reader.GetOrdinal("id"))));
        result.CreationTime = reader.GetDateTime(reader.GetOrdinal("creation_time")).ToUniversalTime();
        result.LastModifiedTime = reader.GetDateTime(reader.GetOrdinal("last_modified_time")).ToUniversalTime();
        result.IMO = (Int32)reader.GetValue(reader.GetOrdinal("imo"));
        result.DateUTC = (string)reader.GetValue(reader.GetOrdinal("date_utc"));
        result.TimeUTC = (string)reader.GetValue(reader.GetOrdinal("time_utc"));
        result.VoyageFrom = (string)reader.GetValue(reader.GetOrdinal("voyage_from"));
        result.VoyageTo = (string)reader.GetValue(reader.GetOrdinal("voyage_to"));
        result.VoyageNumber = (string)reader.GetValue(reader.GetOrdinal("voyage_number"));
        result.OffhireReasons = (string)reader.GetValue(reader.GetOrdinal("offhire_reasons"));
        result.Event = (LogAbstractEventType)reader.GetInt32(reader.GetOrdinal("event"));
        result.TimeSincePreviousReport = reader.GetValue(reader.GetOrdinal("time_since_previous_report")) as float? ?? default;
        result.TimeElapsedSailing = reader.GetValue(reader.GetOrdinal("time_elapsed_sailing")) as float? ?? default;
        result.TimeElapsedAnchoring = reader.GetValue(reader.GetOrdinal("time_elapsed_anchoring")) as float? ?? default;
        result.TimeElapsedDP = reader.GetValue(reader.GetOrdinal("time_elapsed_dp")) as float? ?? default;
        result.TimeElapsedIce = reader.GetValue(reader.GetOrdinal("time_elapsed_ice")) as float? ?? default;
        result.TimeElapsedManeuvering = reader.GetValue(reader.GetOrdinal("time_elapsed_maneuvering")) as float? ?? default;
        result.TimeElapsedWaiting = reader.GetValue(reader.GetOrdinal("time_elapsed_waiting")) as float? ?? default;
        result.TimeElapsedLoadingUnloading = reader.GetValue(reader.GetOrdinal("time_elapsed_loading_unloading")) as float? ?? default;
        result.TimeElapsedDrifting = reader.GetValue(reader.GetOrdinal("time_elapsed_drifting")) as float? ?? default;
        result.Distance = reader.GetValue(reader.GetOrdinal("distance")) as float? ?? default;
        result.LatitudeDegree = reader.GetInt32(reader.GetOrdinal("latitude_degree"));
        result.LatitudeMinutes = reader.GetValue(reader.GetOrdinal("latitude_minutes")) as float? ?? default;
        result.LatitudeNorthSouth = (LatitudeNorthSouth)reader.GetInt32(reader.GetOrdinal("latitude_north_south"));
        result.LongitudeDegree = reader.GetInt32(reader.GetOrdinal("longitude_degree"));
        result.LongitudeMinutes = reader.GetValue(reader.GetOrdinal("longitude_minutes")) as float? ?? default;
        result.LongitudeEastWest = (LongitudeEastWest)reader.GetInt32(reader.GetOrdinal("longitude_east_west"));
        result.CargoMt = reader.GetValue(reader.GetOrdinal("cargo_mt")) as float? ?? default;
        result.CargoM3 = reader.GetValue(reader.GetOrdinal("cargo_m3")) as float? ?? default;
        result.Passengers = reader.GetInt32(reader.GetOrdinal("passengers"));
        result.CargoCEU = reader.GetValue(reader.GetOrdinal("cargo_ceu")) as float? ?? default;
        result.CargoTotalTEU = reader.GetInt32(reader.GetOrdinal("cargo_total_teu"));
        result.CargoTotalFullTEU = reader.GetInt32(reader.GetOrdinal("cargo_total_full_teu"));
        result.CargoFullReeferTEU = reader.GetInt32(reader.GetOrdinal("cargo_full_reefer_teu"));
        result.Reefer20Chilled = reader.GetInt32(reader.GetOrdinal("reefer_20_chilled"));
        result.Reefer40Chilled = reader.GetInt32(reader.GetOrdinal("reefer_40_chilled"));
        result.Reefer20Frozen = reader.GetInt32(reader.GetOrdinal("reefer_20_frozen"));
        result.Reefer40Frozen = reader.GetInt32(reader.GetOrdinal("reefer_40_frozen"));
        result.MEConsumptionHFO = reader.GetValue(reader.GetOrdinal("me_consumption_hfo")) as float? ?? default;
        result.MEConsumptionLFO = reader.GetValue(reader.GetOrdinal("me_consumption_lfo")) as float? ?? default;
        result.MEConsumptionMGO = reader.GetValue(reader.GetOrdinal("me_consumption_mgo")) as float? ?? default;
        result.MEConsumptionMDO = reader.GetValue(reader.GetOrdinal("me_consumption_mdo")) as float? ?? default;
        result.MEConsumptionLSHFO = reader.GetValue(reader.GetOrdinal("me_consumption_lshfo")) as float? ?? default;
        result.MEConsumptionLSLFO = reader.GetValue(reader.GetOrdinal("me_consumption_lslfo")) as float? ?? default;
        result.MEConsumptionLSMGO = reader.GetValue(reader.GetOrdinal("me_consumption_lsmgo")) as float? ?? default;
        result.MEConsumptionULSFO2020 = reader.GetValue(reader.GetOrdinal("me_consumption_ulsfo2020")) as float? ?? default;
        result.MEConsumptionULSLFO2020 = reader.GetValue(reader.GetOrdinal("me_consumption_ulslfo2020")) as float? ?? default;
        result.MEConsumptionULSMDO2020 = reader.GetValue(reader.GetOrdinal("me_consumption_ulsmdo2020")) as float? ?? default;
        result.MEConsumptionULSMGO2020 = reader.GetValue(reader.GetOrdinal("me_consumption_ulsmgo2020")) as float? ?? default;
        result.MEConsumptionVLSFO2020 = reader.GetValue(reader.GetOrdinal("me_consumption_vlsfo2020")) as float? ?? default;
        result.MEConsumptionVLSLFO2020 = reader.GetValue(reader.GetOrdinal("me_consumption_vlslfo2020")) as float? ?? default;
        result.MEConsumptionLPGP = reader.GetValue(reader.GetOrdinal("me_consumption_lpgp")) as float? ?? default;
        result.MEConsumptionLPGB = reader.GetValue(reader.GetOrdinal("me_consumption_lpgb")) as float? ?? default;
        result.MEConsumptionLNG = reader.GetValue(reader.GetOrdinal("me_consumption_lng")) as float? ?? default;
        result.MEConsumptionM = reader.GetValue(reader.GetOrdinal("me_consumption_m")) as float? ?? default;
        result.MEConsumptionE = reader.GetValue(reader.GetOrdinal("me_consumption_e")) as float? ?? default;
        result.MEConsumptionO = reader.GetValue(reader.GetOrdinal("me_consumption_o")) as float? ?? default;
        result.MEConsumptionOType = (string)reader.GetValue(reader.GetOrdinal("me_consumption_o_type"));
        result.AEConsumptionHFO = reader.GetValue(reader.GetOrdinal("ae_consumption_hfo")) as float? ?? default;
        result.AEConsumptionLFO = reader.GetValue(reader.GetOrdinal("ae_consumption_lfo")) as float? ?? default;
        result.AEConsumptionMGO = reader.GetValue(reader.GetOrdinal("ae_consumption_mgo")) as float? ?? default;
        result.AEConsumptionMDO = reader.GetValue(reader.GetOrdinal("ae_consumption_mdo")) as float? ?? default;
        result.AEConsumptionLSHFO = reader.GetValue(reader.GetOrdinal("ae_consumption_lshfo")) as float? ?? default;
        result.AEConsumptionLSLFO = reader.GetValue(reader.GetOrdinal("ae_consumption_lslfo")) as float? ?? default;
        result.AEConsumptionLSMGO = reader.GetValue(reader.GetOrdinal("ae_consumption_lsmgo")) as float? ?? default;
        result.AEConsumptionULSFO2020 = reader.GetValue(reader.GetOrdinal("ae_consumption_ulsfo2020")) as float? ?? default;
        result.AEConsumptionULSLFO2020 = reader.GetValue(reader.GetOrdinal("ae_consumption_ulslfo2020")) as float? ?? default;
        result.AEConsumptionULSMDO2020 = reader.GetValue(reader.GetOrdinal("ae_consumption_ulsmdo2020")) as float? ?? default;
        result.AEConsumptionULSMGO2020 = reader.GetValue(reader.GetOrdinal("ae_consumption_ulsmgo2020")) as float? ?? default;
        result.AEConsumptionVLSFO2020 = reader.GetValue(reader.GetOrdinal("ae_consumption_vlsfo2020")) as float? ?? default;
        result.AEConsumptionVLSLFO2020 = reader.GetValue(reader.GetOrdinal("ae_consumption_vlslfo2020")) as float? ?? default;
        result.AEConsumptionLPGP = reader.GetValue(reader.GetOrdinal("ae_consumption_lpgp")) as float? ?? default;
        result.AEConsumptionLPGB = reader.GetValue(reader.GetOrdinal("ae_consumption_lpgb")) as float? ?? default;
        result.AEConsumptionLNG = reader.GetValue(reader.GetOrdinal("ae_consumption_lng")) as float? ?? default;
        result.AEConsumptionM = reader.GetValue(reader.GetOrdinal("ae_consumption_m")) as float? ?? default;
        result.AEConsumptionE = reader.GetValue(reader.GetOrdinal("ae_consumption_e")) as float? ?? default;
        result.AEConsumptionO = reader.GetValue(reader.GetOrdinal("ae_consumption_o")) as float? ?? default;
        result.AEConsumptionOType = (string)reader.GetValue(reader.GetOrdinal("ae_consumption_o_type"));
        result.AEEmrgConsHFO = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_hfo")) as float? ?? default;
        result.AEEmrgConsLFO = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_lfo")) as float? ?? default;
        result.AEEmrgConsMGO = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_mgo")) as float? ?? default;
        result.AEEmrgConsMDO = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_mdo")) as float? ?? default;
        result.AEEmrgConsLSHFO = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_lshfo")) as float? ?? default;
        result.AEEmrgConsLSLFO = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_lslfo")) as float? ?? default;
        result.AEEmrgConsLSMGO = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_lsmgo")) as float? ?? default;
        result.AEEmrgConsULSFO2020 = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_ulsfo2020")) as float? ?? default;
        result.AEEmrgConsULSLFO2020 = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_ulslfo2020")) as float? ?? default;
        result.AEEmrgConsULSMDO2020 = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_ulsmdo2020")) as float? ?? default;
        result.AEEmrgConsULSMGO2020 = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_ulsmgo2020")) as float? ?? default;
        result.AEEmrgConsVLSFO2020 = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_vlsfo2020")) as float? ?? default;
        result.AEEmrgConsVLSLFO2020 = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_vlslfo2020")) as float? ?? default;
        result.AEEmrgConsLPGP = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_lpgp")) as float? ?? default;
        result.AEEmrgConsLPGB = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_lpgb")) as float? ?? default;
        result.AEEmrgConsLNG = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_lng")) as float? ?? default;
        result.AEEmrgConsM = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_m")) as float? ?? default;
        result.AEEmrgConsE = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_e")) as float? ?? default;
        result.AEEmrgConsO = reader.GetValue(reader.GetOrdinal("ae_emrg_cons_o")) as float? ?? default;
        result.AEEmrgConsOType = (string)reader.GetValue(reader.GetOrdinal("ae_emrg_cons_o_type"));
        result.BoilerConsumptionHFO = reader.GetValue(reader.GetOrdinal("boiler_consumption_hfo")) as float? ?? default;
        result.BoilerConsumptionLFO = reader.GetValue(reader.GetOrdinal("boiler_consumption_lfo")) as float? ?? default;
        result.BoilerConsumptionMGO = reader.GetValue(reader.GetOrdinal("boiler_consumption_mgo")) as float? ?? default;
        result.BoilerConsumptionMDO = reader.GetValue(reader.GetOrdinal("boiler_consumption_mdo")) as float? ?? default;
        result.BoilerConsumptionLSHFO = reader.GetValue(reader.GetOrdinal("boiler_consumption_lshfo")) as float? ?? default;
        result.BoilerConsumptionLSLFO = reader.GetValue(reader.GetOrdinal("boiler_consumption_lslfo")) as float? ?? default;
        result.BoilerConsumptionLSMGO = reader.GetValue(reader.GetOrdinal("boiler_consumption_lsmgo")) as float? ?? default;
        result.BoilerConsumptionULSFO2020 = reader.GetValue(reader.GetOrdinal("boiler_consumption_ulsfo2020")) as float? ?? default;
        result.BoilerConsumptionULSLFO2020 = reader.GetValue(reader.GetOrdinal("boiler_consumption_ulslfo2020")) as float? ?? default;
        result.BoilerConsumptionULSMDO2020 = reader.GetValue(reader.GetOrdinal("boiler_consumption_ulsmdo2020")) as float? ?? default;
        result.BoilerConsumptionULSMGO2020 = reader.GetValue(reader.GetOrdinal("boiler_consumption_ulsmgo2020")) as float? ?? default;
        result.BoilerConsumptionVLSFO2020 = reader.GetValue(reader.GetOrdinal("boiler_consumption_vlsfo2020")) as float? ?? default;
        result.BoilerConsumptionVLSLFO2020 = reader.GetValue(reader.GetOrdinal("boiler_consumption_vlslfo2020")) as float? ?? default;
        result.BoilerConsumptionLPGP = reader.GetValue(reader.GetOrdinal("boiler_consumption_lpgp")) as float? ?? default;
        result.BoilerConsumptionLPGB = reader.GetValue(reader.GetOrdinal("boiler_consumption_lpgb")) as float? ?? default;
        result.BoilerConsumptionLNG = reader.GetValue(reader.GetOrdinal("boiler_consumption_lng")) as float? ?? default;
        result.BoilerConsumptionM = reader.GetValue(reader.GetOrdinal("boiler_consumption_m")) as float? ?? default;
        result.BoilerConsumptionE = reader.GetValue(reader.GetOrdinal("boiler_consumption_e")) as float? ?? default;
        result.BoilerConsumptionO = reader.GetValue(reader.GetOrdinal("boiler_consumption_o")) as float? ?? default;
        result.BoilerConsumptionOType = (string)reader.GetValue(reader.GetOrdinal("boiler_consumption_o_type"));
        result.InertGasConsumptionHFO = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_hfo")) as float? ?? default;
        result.InertGasConsumptionLFO = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_lfo")) as float? ?? default;
        result.InertGasConsumptionMGO = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_mgo")) as float? ?? default;
        result.InertGasConsumptionMDO = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_mdo")) as float? ?? default;
        result.InertGasConsumptionLSHFO = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_lshfo")) as float? ?? default;
        result.InertGasConsumptionLSLFO = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_lslfo")) as float? ?? default;
        result.InertGasConsumptionLSMGO = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_lsmgo")) as float? ?? default;
        result.InertGasConsumptionULSFO2020 = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_ulsfo2020")) as float? ?? default;
        result.InertGasConsumptionULSLFO2020 = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_ulslfo2020")) as float? ?? default;
        result.InertGasConsumptionULSMDO2020 = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_ulsmdo2020")) as float? ?? default;
        result.InertGasConsumptionULSMGO2020 = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_ulsmgo2020")) as float? ?? default;
        result.InertGasConsumptionVLSFO2020 = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_vlsfo2020")) as float? ?? default;
        result.InertGasConsumptionVLSLFO2020 = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_vlslfo2020")) as float? ?? default;
        result.InertGasConsumptionLPGP = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_lpgp")) as float? ?? default;
        result.InertGasConsumptionLPGB = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_lpgb")) as float? ?? default;
        result.InertGasConsumptionLNG = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_lng")) as float? ?? default;
        result.InertGasConsumptionM = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_m")) as float? ?? default;
        result.InertGasConsumptionE = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_e")) as float? ?? default;
        result.InertGasConsumptionO = reader.GetValue(reader.GetOrdinal("inert_gas_consumption_o")) as float? ?? default;
        result.InertGasConsumptionOType = (string)reader.GetValue(reader.GetOrdinal("inert_gas_consumption_o_type"));
        result.IncineratorConsumptionO = reader.GetValue(reader.GetOrdinal("incinerator_consumption_o")) as float? ?? default;
        result.IncineratorConsumptionOType = (string)reader.GetValue(reader.GetOrdinal("incinerator_consumption_o_type"));
        result.HFOROB = reader.GetValue(reader.GetOrdinal("hfo_rob")) as float? ?? default;
        result.LFOROB = reader.GetValue(reader.GetOrdinal("lfo_rob")) as float? ?? default;
        result.MGOROB = reader.GetValue(reader.GetOrdinal("mgo_rob")) as float? ?? default;
        result.MDOROB = reader.GetValue(reader.GetOrdinal("mdo_rob")) as float? ?? default;
        result.LSHFOROB = reader.GetValue(reader.GetOrdinal("lshfo_rob")) as float? ?? default;
        result.LSLFOROB = reader.GetValue(reader.GetOrdinal("lslfo_rob")) as float? ?? default;
        result.LSMGOROB = reader.GetValue(reader.GetOrdinal("lsmgo_rob")) as float? ?? default;
        result.ULSFO2020ROB = reader.GetValue(reader.GetOrdinal("ulsfo2020_rob")) as float? ?? default;
        result.ULSLFO2020ROB = reader.GetValue(reader.GetOrdinal("ulslfo2020_rob")) as float? ?? default;
        result.ULSMDO2020ROB = reader.GetValue(reader.GetOrdinal("ulsmdo2020_rob")) as float? ?? default;
        result.ULSMGO2020ROB = reader.GetValue(reader.GetOrdinal("ulsmgo2020_rob")) as float? ?? default;
        result.VLSFO2020ROB = reader.GetValue(reader.GetOrdinal("vlsfo2020_rob")) as float? ?? default;
        result.VLSLFO2020ROB = reader.GetValue(reader.GetOrdinal("vlslfo2020_rob")) as float? ?? default;
        result.LPGPROB = reader.GetValue(reader.GetOrdinal("lpgp_rob")) as float? ?? default;
        result.LPGBROB = reader.GetValue(reader.GetOrdinal("lpgb_rob")) as float? ?? default;
        result.LNGROB = reader.GetValue(reader.GetOrdinal("lng_rob")) as float? ?? default;
        result.MethanolROB = reader.GetValue(reader.GetOrdinal("methanol_rob")) as float? ?? default;
        result.EthanolROB = reader.GetValue(reader.GetOrdinal("ethanol_rob")) as float? ?? default;
        result.OROB = reader.GetValue(reader.GetOrdinal("o_rob")) as float? ?? default;
        result.OROBType = (string)reader.GetValue(reader.GetOrdinal("o_rob_type"));
        result.CargoHeatingConsumptionHFO = reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_hfo")) as float? ?? default;
        result.CargoHeatingConsumptionLFO = reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_lfo")) as float? ?? default;
        result.CargoHeatingConsumptionMGO = reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_mgo")) as float? ?? default;
        result.CargoHeatingConsumptionMDO = reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_mdo")) as float? ?? default;
        result.CargoHeatingConsumptionLSHFO = reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_lshfo")) as float? ?? default;
        result.CargoHeatingConsumptionLSLFO = reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_lslfo")) as float? ?? default;
        result.CargoHeatingConsumptionLSMGO = reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_lsmgo")) as float? ?? default;
        result.CargoHeatingConsumptionULSFO2020 =
            reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_ulsfo2020")) as float? ?? default;
        result.CargoHeatingConsumptionULSLFO2020 =
            reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_ulslfo2020")) as float? ?? default;
        result.CargoHeatingConsumptionULSMDO2020 =
            reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_ulsmdo2020")) as float? ?? default;
        result.CargoHeatingConsumptionULSMGO2020 =
            reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_ulsmgo2020")) as float? ?? default;
        result.CargoHeatingConsumptionVLSFO2020 =
            reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_vlsfo2020")) as float? ?? default;
        result.CargoHeatingConsumptionVLSLFO2020 =
            reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_vlslfo2020")) as float? ?? default;
        result.CargoHeatingConsumptionLPGP = reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_lpgp")) as float? ?? default;
        result.CargoHeatingConsumptionLPGB = reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_lpgb")) as float? ?? default;
        result.CargoHeatingConsumptionLNG = reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_lng")) as float? ?? default;
        result.CargoHeatingConsumptionM = reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_m")) as float? ?? default;
        result.CargoHeatingConsumptionE = reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_e")) as float? ?? default;
        result.CargoHeatingConsumptionO = reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_o")) as float? ?? default;
        result.CargoHeatingConsumptionOType = (string)reader.GetValue(reader.GetOrdinal("cargo_heating_consumption_o_type"));
        result.DPPCargoPumpConsumptionMDO = reader.GetValue(reader.GetOrdinal("dpp_cargo_pump_consumption_mdo")) as float? ?? default;
        result.DPPCargoPumpConsumptionO = reader.GetValue(reader.GetOrdinal("dpp_cargo_pump_consumption_o")) as float? ?? default;
        result.DPPCargoPumpConsumptionOType = (string)reader.GetValue(reader.GetOrdinal("dpp_cargo_pump_consumption_o_type"));
        result.DPConsumptionHFO = reader.GetValue(reader.GetOrdinal("dp_consumption_hfo")) as float? ?? default;
        result.DPConsumptionLFO = reader.GetValue(reader.GetOrdinal("dp_consumption_lfo")) as float? ?? default;
        result.DPConsumptionMGO = reader.GetValue(reader.GetOrdinal("dp_consumption_mgo")) as float? ?? default;
        result.DPConsumptionMDO = reader.GetValue(reader.GetOrdinal("dp_consumption_mdo")) as float? ?? default;
        result.DPConsumptionLSHFO = reader.GetValue(reader.GetOrdinal("dp_consumption_lshfo")) as float? ?? default;
        result.DPConsumptionLSLFO = reader.GetValue(reader.GetOrdinal("dp_consumption_lslfo")) as float? ?? default;
        result.DPConsumptionLSMGO = reader.GetValue(reader.GetOrdinal("dp_consumption_lsmgo")) as float? ?? default;
        result.DPConsumptionULSFO2020 = reader.GetValue(reader.GetOrdinal("dp_consumption_ulsfo2020")) as float? ?? default;
        result.DPConsumptionULSLFO2020 = reader.GetValue(reader.GetOrdinal("dp_consumption_ulslfo2020")) as float? ?? default;
        result.DPConsumptionULSMDO2020 = reader.GetValue(reader.GetOrdinal("dp_consumption_ulsmdo2020")) as float? ?? default;
        result.DPConsumptionULSMGO2020 = reader.GetValue(reader.GetOrdinal("dp_consumption_ulsmgo2020")) as float? ?? default;
        result.DPConsumptionVLSFO2020 = reader.GetValue(reader.GetOrdinal("dp_consumption_vlsfo2020")) as float? ?? default;
        result.DPConsumptionVLSLFO2020 = reader.GetValue(reader.GetOrdinal("dp_consumption_vlslfo2020")) as float? ?? default;
        result.DPConsumptionLPGP = reader.GetValue(reader.GetOrdinal("dp_consumption_lpgp")) as float? ?? default;
        result.DPConsumptionLPGB = reader.GetValue(reader.GetOrdinal("dp_consumption_lpgb")) as float? ?? default;
        result.DPConsumptionLNG = reader.GetValue(reader.GetOrdinal("dp_consumption_lng")) as float? ?? default;
        result.DPConsumptionM = reader.GetValue(reader.GetOrdinal("dp_consumption_m")) as float? ?? default;
        result.DPConsumptionE = reader.GetValue(reader.GetOrdinal("dp_consumption_e")) as float? ?? default;
        result.DPConsumptionO = reader.GetValue(reader.GetOrdinal("dp_consumption_o")) as float? ?? default;
        result.DPConsumptionOType = (string)reader.GetValue(reader.GetOrdinal("dp_consumption_o_type"));
        result.ReeferWork = reader.GetValue(reader.GetOrdinal("reefer_work")) as float? ?? default;
        result.ReeferSFOC = reader.GetValue(reader.GetOrdinal("reefer_sfoc")) as float? ?? default;
        result.ReeferFuelType = reader.GetValue(reader.GetOrdinal("reefer_fuel_type")) as FuelType? ?? default;
        result.ReeferFuelBDN = (string)reader.GetValue(reader.GetOrdinal("reefer_fuel_bdn"));
        result.CargoCoolingWork = reader.GetValue(reader.GetOrdinal("cargo_cooling_work")) as float? ?? default;
        result.CargoCoolingSFOC = reader.GetValue(reader.GetOrdinal("cargo_cooling_sfoc")) as float? ?? default;
        result.CargoCoolingFuelType = reader.GetValue(reader.GetOrdinal("cargo_cooling_fuel_type")) as FuelType? ?? default;
        result.CargoCoolingFuelBDN = (string)reader.GetValue(reader.GetOrdinal("cargo_cooling_fuel_bdn"));
        result.DischargePumpWork = reader.GetValue(reader.GetOrdinal("discharge_pump_work")) as float? ?? default;
        result.DischargePumpSFOC = reader.GetValue(reader.GetOrdinal("discharge_pump_sfoc")) as float? ?? default;
        result.DischargePumpFuelType = reader.GetValue(reader.GetOrdinal("discharge_pump_fuel_type")) as FuelType? ?? default;
        result.DischargePumpFuelBDN = (string)reader.GetValue(reader.GetOrdinal("discharge_pump_fuel_bdn"));
        result.ShoreSideElectricityReception = reader.GetValue(reader.GetOrdinal("shore_side_electricity_reception")) as float? ?? default;

        return result;
    }

    /// <summary>
    /// 获取 insert 时的参数
    /// </summary>
    /// <param name="logAbstract"></param>
    /// <param name="dbName"></param>
    /// <param name="subTableName"></param>
    /// <returns></returns>
    private static (string insertCommandText, List<KeyValuePair<string, object?>> insertCommandParameters)
        GetInsertCommandTextAndParameters(LogAbstract logAbstract, string dbName, string subTableName)
    {
        string commandText =
            $"INSERT INTO {dbName}.{subTableName} USING {dbName}.log_abstract (id) TAGS ('{logAbstract.Id}') (ts, creation_time, last_modified_time, imo, date_utc, time_utc, voyage_from, voyage_to, voyage_number, offhire_reasons, event, time_since_previous_report, time_elapsed_sailing, time_elapsed_anchoring, time_elapsed_dp, time_elapsed_ice, time_elapsed_maneuvering, time_elapsed_waiting, time_elapsed_loading_unloading, time_elapsed_drifting, distance, latitude_degree, latitude_minutes, latitude_north_south, longitude_degree, longitude_minutes, longitude_east_west, cargo_mt, cargo_m3, passengers, cargo_ceu, cargo_total_teu, cargo_total_full_teu, cargo_full_reefer_teu, reefer_20_chilled, reefer_40_chilled, reefer_20_frozen, reefer_40_frozen, me_consumption_hfo, me_consumption_lfo, me_consumption_mgo, me_consumption_mdo, me_consumption_lshfo, me_consumption_lslfo, me_consumption_lsmgo, me_consumption_ulsfo2020, me_consumption_ulslfo2020, me_consumption_ulsmdo2020, me_consumption_ulsmgo2020, me_consumption_vlsfo2020, me_consumption_vlslfo2020, me_consumption_lpgp, me_consumption_lpgb, me_consumption_lng, me_consumption_m, me_consumption_e, me_consumption_o, me_consumption_o_type, ae_consumption_hfo, ae_consumption_lfo, ae_consumption_mgo, ae_consumption_mdo, ae_consumption_lshfo, ae_consumption_lslfo, ae_consumption_lsmgo, ae_consumption_ulsfo2020, ae_consumption_ulslfo2020, ae_consumption_ulsmdo2020, ae_consumption_ulsmgo2020, ae_consumption_vlsfo2020, ae_consumption_vlslfo2020, ae_consumption_lpgp, ae_consumption_lpgb, ae_consumption_lng, ae_consumption_m, ae_consumption_e, ae_consumption_o, ae_consumption_o_type, ae_emrg_cons_hfo, ae_emrg_cons_lfo, ae_emrg_cons_mgo, ae_emrg_cons_mdo, ae_emrg_cons_lshfo, ae_emrg_cons_lslfo, ae_emrg_cons_lsmgo, ae_emrg_cons_ulsfo2020, ae_emrg_cons_ulslfo2020, ae_emrg_cons_ulsmdo2020, ae_emrg_cons_ulsmgo2020, ae_emrg_cons_vlsfo2020, ae_emrg_cons_vlslfo2020, ae_emrg_cons_lpgp, ae_emrg_cons_lpgb, ae_emrg_cons_lng, ae_emrg_cons_m, ae_emrg_cons_e, ae_emrg_cons_o, ae_emrg_cons_o_type, boiler_consumption_hfo, boiler_consumption_lfo, boiler_consumption_mgo, boiler_consumption_mdo, boiler_consumption_lshfo, boiler_consumption_lslfo, boiler_consumption_lsmgo, boiler_consumption_ulsfo2020, boiler_consumption_ulslfo2020, boiler_consumption_ulsmdo2020, boiler_consumption_ulsmgo2020, boiler_consumption_vlsfo2020, boiler_consumption_vlslfo2020, boiler_consumption_lpgp, boiler_consumption_lpgb, boiler_consumption_lng, boiler_consumption_m, boiler_consumption_e, boiler_consumption_o, boiler_consumption_o_type, inert_gas_consumption_hfo, inert_gas_consumption_lfo, inert_gas_consumption_mgo, inert_gas_consumption_mdo, inert_gas_consumption_lshfo, inert_gas_consumption_lslfo, inert_gas_consumption_lsmgo, inert_gas_consumption_ulsfo2020, inert_gas_consumption_ulslfo2020, inert_gas_consumption_ulsmdo2020, inert_gas_consumption_ulsmgo2020, inert_gas_consumption_vlsfo2020, inert_gas_consumption_vlslfo2020, inert_gas_consumption_lpgp, inert_gas_consumption_lpgb, inert_gas_consumption_lng, inert_gas_consumption_m, inert_gas_consumption_e, inert_gas_consumption_o, inert_gas_consumption_o_type, incinerator_consumption_o, incinerator_consumption_o_type, hfo_rob, lfo_rob, mgo_rob, mdo_rob, lshfo_rob, lslfo_rob, lsmgo_rob, ulsfo2020_rob, ulslfo2020_rob, ulsmdo2020_rob, ulsmgo2020_rob, vlsfo2020_rob, vlslfo2020_rob, lpgp_rob, lpgb_rob, lng_rob, methanol_rob, ethanol_rob, o_rob, o_rob_type, cargo_heating_consumption_hfo, cargo_heating_consumption_lfo, cargo_heating_consumption_mgo, cargo_heating_consumption_mdo, cargo_heating_consumption_lshfo, cargo_heating_consumption_lslfo, cargo_heating_consumption_lsmgo, cargo_heating_consumption_ulsfo2020, cargo_heating_consumption_ulslfo2020, cargo_heating_consumption_ulsmdo2020, cargo_heating_consumption_ulsmgo2020, cargo_heating_consumption_vlsfo2020, cargo_heating_consumption_vlslfo2020, cargo_heating_consumption_lpgp, cargo_heating_consumption_lpgb, cargo_heating_consumption_lng, cargo_heating_consumption_m, cargo_heating_consumption_e, cargo_heating_consumption_o, cargo_heating_consumption_o_type, dpp_cargo_pump_consumption_mdo, dpp_cargo_pump_consumption_o, dpp_cargo_pump_consumption_o_type, dp_consumption_hfo, dp_consumption_lfo, dp_consumption_mgo, dp_consumption_mdo, dp_consumption_lshfo, dp_consumption_lslfo, dp_consumption_lsmgo, dp_consumption_ulsfo2020, dp_consumption_ulslfo2020, dp_consumption_ulsmdo2020, dp_consumption_ulsmgo2020, dp_consumption_vlsfo2020, dp_consumption_vlslfo2020, dp_consumption_lpgp, dp_consumption_lpgb, dp_consumption_lng, dp_consumption_m, dp_consumption_e, dp_consumption_o, dp_consumption_o_type, reefer_work, reefer_sfoc, reefer_fuel_type, reefer_fuel_bdn, cargo_cooling_work, cargo_cooling_sfoc, cargo_cooling_fuel_type, cargo_cooling_fuel_bdn, discharge_pump_work, discharge_pump_sfoc, discharge_pump_fuel_type, discharge_pump_fuel_bdn, shore_side_electricity_reception) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
        List<KeyValuePair<string, object?>> insertCommandParameters =
        [
            new("@0", DateTime.SpecifyKind(logAbstract.Ts, DateTimeKind.Utc)),
            new("@1", DateTime.SpecifyKind(logAbstract.CreationTime, DateTimeKind.Utc)),
            new("@2", DateTime.SpecifyKind(logAbstract.LastModifiedTime, DateTimeKind.Utc)),
            new("@3", (int)logAbstract.IMO),
            new("@4", logAbstract.DateUTC),
            new("@5", logAbstract.TimeUTC),
            new("@6", logAbstract.VoyageFrom),
            new("@7", logAbstract.VoyageTo),
            new("@8", logAbstract.VoyageNumber),
            new("@9", logAbstract.OffhireReasons ?? null),
            new("@10", (int)logAbstract.Event),
            new("@11", logAbstract.TimeSincePreviousReport),
            new("@12", logAbstract.TimeElapsedSailing),
            new("@13", logAbstract.TimeElapsedAnchoring),
            new("@14", logAbstract.TimeElapsedDP),
            new("@15", logAbstract.TimeElapsedIce),
            new("@16", logAbstract.TimeElapsedManeuvering),
            new("@17", logAbstract.TimeElapsedWaiting),
            new("@18", logAbstract.TimeElapsedLoadingUnloading),
            new("@19", logAbstract.TimeElapsedDrifting),
            new("@20", logAbstract.Distance),
            new("@21", (int)logAbstract.LatitudeDegree),
            new("@22", logAbstract.LatitudeMinutes),
            new("@23", (int)logAbstract.LatitudeNorthSouth),
            new("@24", (int)logAbstract.LongitudeDegree),
            new("@25", logAbstract.LongitudeMinutes),
            new("@26", (int)logAbstract.LongitudeEastWest),
            new("@27", logAbstract.CargoMt),
            new("@28", logAbstract.CargoM3),
            new("@29", (int)logAbstract.Passengers),
            new("@30", logAbstract.CargoCEU),
            new("@31", (int)logAbstract.CargoTotalTEU),
            new("@32", (int)logAbstract.CargoTotalFullTEU),
            new("@33", (int)logAbstract.CargoFullReeferTEU),
            new("@34", (int)logAbstract.Reefer20Chilled),
            new("@35", (int)logAbstract.Reefer40Chilled),
            new("@36", (int)logAbstract.Reefer20Frozen),
            new("@37", (int)logAbstract.Reefer40Frozen),
            new("@38", logAbstract.MEConsumptionHFO),
            new("@39", logAbstract.MEConsumptionLFO),
            new("@40", logAbstract.MEConsumptionMGO),
            new("@41", logAbstract.MEConsumptionMDO),
            new("@42", logAbstract.MEConsumptionLSHFO),
            new("@43", logAbstract.MEConsumptionLSLFO),
            new("@44", logAbstract.MEConsumptionLSMGO),
            new("@45", logAbstract.MEConsumptionULSFO2020),
            new("@46", logAbstract.MEConsumptionULSLFO2020),
            new("@47", logAbstract.MEConsumptionULSMDO2020),
            new("@48", logAbstract.MEConsumptionULSMGO2020),
            new("@49", logAbstract.MEConsumptionVLSFO2020),
            new("@50", logAbstract.MEConsumptionVLSLFO2020),
            new("@51", logAbstract.MEConsumptionLPGP),
            new("@52", logAbstract.MEConsumptionLPGB),
            new("@53", logAbstract.MEConsumptionLNG),
            new("@54", logAbstract.MEConsumptionM),
            new("@55", logAbstract.MEConsumptionE),
            new("@56", logAbstract.MEConsumptionO),
            new("@57", logAbstract.MEConsumptionOType ?? null),
            new("@58", logAbstract.AEConsumptionHFO),
            new("@59", logAbstract.AEConsumptionLFO),
            new("@60", logAbstract.AEConsumptionMGO),
            new("@61", logAbstract.AEConsumptionMDO),
            new("@62", logAbstract.AEConsumptionLSHFO),
            new("@63", logAbstract.AEConsumptionLSLFO),
            new("@64", logAbstract.AEConsumptionLSMGO),
            new("@65", logAbstract.AEConsumptionULSFO2020),
            new("@66", logAbstract.AEConsumptionULSLFO2020),
            new("@67", logAbstract.AEConsumptionULSMDO2020),
            new("@68", logAbstract.AEConsumptionULSMGO2020),
            new("@69", logAbstract.AEConsumptionVLSFO2020),
            new("@70", logAbstract.AEConsumptionVLSLFO2020),
            new("@71", logAbstract.AEConsumptionLPGP),
            new("@72", logAbstract.AEConsumptionLPGB),
            new("@73", logAbstract.AEConsumptionLNG),
            new("@74", logAbstract.AEConsumptionM),
            new("@75", logAbstract.AEConsumptionE),
            new("@76", logAbstract.AEConsumptionO),
            new("@77", logAbstract.AEConsumptionOType ?? null),
            new("@78", logAbstract.AEEmrgConsHFO),
            new("@79", logAbstract.AEEmrgConsLFO),
            new("@80", logAbstract.AEEmrgConsMGO),
            new("@81", logAbstract.AEEmrgConsMDO),
            new("@82", logAbstract.AEEmrgConsLSHFO),
            new("@83", logAbstract.AEEmrgConsLSLFO),
            new("@84", logAbstract.AEEmrgConsLSMGO),
            new("@85", logAbstract.AEEmrgConsULSFO2020),
            new("@86", logAbstract.AEEmrgConsULSLFO2020),
            new("@87", logAbstract.AEEmrgConsULSMDO2020),
            new("@88", logAbstract.AEEmrgConsULSMGO2020),
            new("@89", logAbstract.AEEmrgConsVLSFO2020),
            new("@90", logAbstract.AEEmrgConsVLSLFO2020),
            new("@91", logAbstract.AEEmrgConsLPGP),
            new("@92", logAbstract.AEEmrgConsLPGB),
            new("@93", logAbstract.AEEmrgConsLNG),
            new("@94", logAbstract.AEEmrgConsM),
            new("@95", logAbstract.AEEmrgConsE),
            new("@96", logAbstract.AEEmrgConsO),
            new("@97", logAbstract.AEEmrgConsOType ?? null),
            new("@98", logAbstract.BoilerConsumptionHFO),
            new("@99", logAbstract.BoilerConsumptionLFO),
            new("@100", logAbstract.BoilerConsumptionMGO),
            new("@101", logAbstract.BoilerConsumptionMDO),
            new("@102", logAbstract.BoilerConsumptionLSHFO),
            new("@103", logAbstract.BoilerConsumptionLSLFO),
            new("@104", logAbstract.BoilerConsumptionLSMGO),
            new("@105", logAbstract.BoilerConsumptionULSFO2020),
            new("@106", logAbstract.BoilerConsumptionULSLFO2020),
            new("@107", logAbstract.BoilerConsumptionULSMDO2020),
            new("@108", logAbstract.BoilerConsumptionULSMGO2020),
            new("@109", logAbstract.BoilerConsumptionVLSFO2020),
            new("@110", logAbstract.BoilerConsumptionVLSLFO2020),
            new("@111", logAbstract.BoilerConsumptionLPGP),
            new("@112", logAbstract.BoilerConsumptionLPGB),
            new("@113", logAbstract.BoilerConsumptionLNG),
            new("@114", logAbstract.BoilerConsumptionM),
            new("@115", logAbstract.BoilerConsumptionE),
            new("@116", logAbstract.BoilerConsumptionO),
            new("@117", logAbstract.BoilerConsumptionOType ?? null),
            new("@118", logAbstract.InertGasConsumptionHFO),
            new("@119", logAbstract.InertGasConsumptionLFO),
            new("@120", logAbstract.InertGasConsumptionMGO),
            new("@121", logAbstract.InertGasConsumptionMDO),
            new("@122", logAbstract.InertGasConsumptionLSHFO),
            new("@123", logAbstract.InertGasConsumptionLSLFO),
            new("@124", logAbstract.InertGasConsumptionLSMGO),
            new("@125", logAbstract.InertGasConsumptionULSFO2020),
            new("@126", logAbstract.InertGasConsumptionULSLFO2020),
            new("@127", logAbstract.InertGasConsumptionULSMDO2020),
            new("@128", logAbstract.InertGasConsumptionULSMGO2020),
            new("@129", logAbstract.InertGasConsumptionVLSFO2020),
            new("@130", logAbstract.InertGasConsumptionVLSLFO2020),
            new("@131", logAbstract.InertGasConsumptionLPGP),
            new("@132", logAbstract.InertGasConsumptionLPGB),
            new("@133", logAbstract.InertGasConsumptionLNG),
            new("@134", logAbstract.InertGasConsumptionM),
            new("@135", logAbstract.InertGasConsumptionE),
            new("@136", logAbstract.InertGasConsumptionO),
            new("@137", logAbstract.InertGasConsumptionOType ?? null),
            new("@138", logAbstract.IncineratorConsumptionO),
            new("@139", logAbstract.IncineratorConsumptionOType ?? null),
            new("@140", logAbstract.HFOROB),
            new("@141", logAbstract.LFOROB),
            new("@142", logAbstract.MGOROB),
            new("@143", logAbstract.MDOROB),
            new("@144", logAbstract.LSHFOROB),
            new("@145", logAbstract.LSLFOROB),
            new("@146", logAbstract.LSMGOROB),
            new("@147", logAbstract.ULSFO2020ROB),
            new("@148", logAbstract.ULSLFO2020ROB),
            new("@149", logAbstract.ULSMDO2020ROB),
            new("@150", logAbstract.ULSMGO2020ROB),
            new("@151", logAbstract.VLSFO2020ROB),
            new("@152", logAbstract.VLSLFO2020ROB),
            new("@153", logAbstract.LPGPROB),
            new("@154", logAbstract.LPGBROB),
            new("@155", logAbstract.LNGROB),
            new("@156", logAbstract.MethanolROB),
            new("@157", logAbstract.EthanolROB),
            new("@158", logAbstract.OROB),
            new("@159", logAbstract.OROBType ?? null),
            new("@160", logAbstract.CargoHeatingConsumptionHFO),
            new("@161", logAbstract.CargoHeatingConsumptionLFO),
            new("@162", logAbstract.CargoHeatingConsumptionMGO),
            new("@163", logAbstract.CargoHeatingConsumptionMDO),
            new("@164", logAbstract.CargoHeatingConsumptionLSHFO),
            new("@165", logAbstract.CargoHeatingConsumptionLSLFO),
            new("@166", logAbstract.CargoHeatingConsumptionLSMGO),
            new("@167", logAbstract.CargoHeatingConsumptionULSFO2020),
            new("@168", logAbstract.CargoHeatingConsumptionULSLFO2020),
            new("@169", logAbstract.CargoHeatingConsumptionULSMDO2020),
            new("@170", logAbstract.CargoHeatingConsumptionULSMGO2020),
            new("@171", logAbstract.CargoHeatingConsumptionVLSFO2020),
            new("@172", logAbstract.CargoHeatingConsumptionVLSLFO2020),
            new("@173", logAbstract.CargoHeatingConsumptionLPGP),
            new("@174", logAbstract.CargoHeatingConsumptionLPGB),
            new("@175", logAbstract.CargoHeatingConsumptionLNG),
            new("@176", logAbstract.CargoHeatingConsumptionM),
            new("@177", logAbstract.CargoHeatingConsumptionE),
            new("@178", logAbstract.CargoHeatingConsumptionO),
            new("@179", logAbstract.CargoHeatingConsumptionOType ?? null),
            new("@180", logAbstract.DPPCargoPumpConsumptionMDO),
            new("@181", logAbstract.DPPCargoPumpConsumptionO),
            new("@182", logAbstract.DPPCargoPumpConsumptionOType ?? null),
            new("@183", logAbstract.DPConsumptionHFO),
            new("@184", logAbstract.DPConsumptionLFO),
            new("@185", logAbstract.DPConsumptionMGO),
            new("@186", logAbstract.DPConsumptionMDO),
            new("@187", logAbstract.DPConsumptionLSHFO),
            new("@188", logAbstract.DPConsumptionLSLFO),
            new("@189", logAbstract.DPConsumptionLSMGO),
            new("@190", logAbstract.DPConsumptionULSFO2020),
            new("@191", logAbstract.DPConsumptionULSLFO2020),
            new("@192", logAbstract.DPConsumptionULSMDO2020),
            new("@193", logAbstract.DPConsumptionULSMGO2020),
            new("@194", logAbstract.DPConsumptionVLSFO2020),
            new("@195", logAbstract.DPConsumptionVLSLFO2020),
            new("@196", logAbstract.DPConsumptionLPGP),
            new("@197", logAbstract.DPConsumptionLPGB),
            new("@198", logAbstract.DPConsumptionLNG),
            new("@199", logAbstract.DPConsumptionM),
            new("@200", logAbstract.DPConsumptionE),
            new("@201", logAbstract.DPConsumptionO),
            new("@202", logAbstract.DPConsumptionOType ?? null),
            new("@203", logAbstract.ReeferWork),
            new("@204", logAbstract.ReeferSFOC),
            new("@205", (int?)logAbstract.ReeferFuelType ?? null),
            new("@206", logAbstract.ReeferFuelBDN ?? null),
            new("@207", logAbstract.CargoCoolingWork),
            new("@208", logAbstract.CargoCoolingSFOC),
            new("@209", (int?)logAbstract.CargoCoolingFuelType ?? null),
            new("@210", logAbstract.CargoCoolingFuelBDN ?? null),
            new("@211", logAbstract.DischargePumpWork),
            new("@212", logAbstract.DischargePumpSFOC),
            new("@213", (int?)logAbstract.DischargePumpFuelType ?? null),
            new("@214", logAbstract.DischargePumpFuelBDN ?? null),
            new("@215", logAbstract.ShoreSideElectricityReception),
        ];
        return (commandText, insertCommandParameters);
    }
}